<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>知识点 | fengrixin</title>
    <meta name="generator" content="VuePress 1.8.2">
    <link rel="icon" href="/favicon.ico">
    <script>
         (function(){
            var html = document.createElement('script');
            html.src = 'https://www.googletagmanager.com/gtag/js?id=UA-166891571-1';
            var script = document.getElementsByTagName('script')[0]'
            script.parentNode.insertBefore(html, script);
            
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments)}
            gtag('js', new Date());
            gtag('config', 'UA-166891571-1');
         })();
        </script>
    <meta name="description" content="I don't know anything with certainty, but seeing the stars makes me dream.">
    <meta name="keywords" content="冯日新, fengrixin, rixin, 飘渺云轩">
    <meta name="author" content="rixin, s2675563468, fengrixin@yeah.net">
    <meta name="copyright" content="rixin">
    <meta name="renderer" content="webkit">
    
    <link rel="preload" href="/assets/css/0.styles.52cdc27a.css" as="style"><link rel="preload" href="/assets/js/app.0696c23a.js" as="script"><link rel="preload" href="/assets/js/2.96f039f8.js" as="script"><link rel="preload" href="/assets/js/17.c016c8f3.js" as="script"><link rel="prefetch" href="/assets/js/10.473b7d15.js"><link rel="prefetch" href="/assets/js/11.0c193dec.js"><link rel="prefetch" href="/assets/js/12.c4d9d484.js"><link rel="prefetch" href="/assets/js/13.dce50cfa.js"><link rel="prefetch" href="/assets/js/14.eecb5cc3.js"><link rel="prefetch" href="/assets/js/15.e0473034.js"><link rel="prefetch" href="/assets/js/16.25b14741.js"><link rel="prefetch" href="/assets/js/18.71195568.js"><link rel="prefetch" href="/assets/js/19.1dfd44c0.js"><link rel="prefetch" href="/assets/js/20.abde37ca.js"><link rel="prefetch" href="/assets/js/21.af59917b.js"><link rel="prefetch" href="/assets/js/22.d2f7b52b.js"><link rel="prefetch" href="/assets/js/23.ec5c07a5.js"><link rel="prefetch" href="/assets/js/24.eae97f7d.js"><link rel="prefetch" href="/assets/js/25.2f09818a.js"><link rel="prefetch" href="/assets/js/26.7ae2d77c.js"><link rel="prefetch" href="/assets/js/27.a3963c70.js"><link rel="prefetch" href="/assets/js/28.eadcc4e5.js"><link rel="prefetch" href="/assets/js/29.61cf8d1d.js"><link rel="prefetch" href="/assets/js/3.dd8204a7.js"><link rel="prefetch" href="/assets/js/30.7db889fa.js"><link rel="prefetch" href="/assets/js/31.fb075f3c.js"><link rel="prefetch" href="/assets/js/4.cf123337.js"><link rel="prefetch" href="/assets/js/5.abe0fc83.js"><link rel="prefetch" href="/assets/js/6.d9ded6eb.js"><link rel="prefetch" href="/assets/js/7.a054e416.js"><link rel="prefetch" href="/assets/js/8.f0b3a07f.js"><link rel="prefetch" href="/assets/js/9.f6495dca.js">
    <link rel="stylesheet" href="/assets/css/0.styles.52cdc27a.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><!----> <span class="site-name">fengrixin</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="地基" class="dropdown-title"><span class="title">地基</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/learn/algorithm/" class="nav-link">数据结构和算法</a></li><li class="dropdown-item"><!----> <a href="/learn/browser/" class="nav-link">浏览器工作原理</a></li><li class="dropdown-item"><!----> <a href="/learn/js/es6.html" class="nav-link">JavaScript</a></li><li class="dropdown-item"><!----> <a href="/learn/css/" class="nav-link">CSS</a></li><li class="dropdown-item"><!----> <a href="/learn/html/" class="nav-link">HTML</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="楼层" class="dropdown-title"><span class="title">楼层</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/learn/vue/" class="nav-link">Vue</a></li><li class="dropdown-item"><!----> <a href="/learn/node/" class="nav-link">Node.js</a></li><li class="dropdown-item"><!----> <a href="/learn/mini/index.html" class="nav-link">小程序</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="电梯" class="dropdown-title"><span class="title">电梯</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/learn/tools/chain.html" class="nav-link">工具链</a></li><li class="dropdown-item"><!----> <a href="/learn/tools/publish.html" class="nav-link">发布系统</a></li><li class="dropdown-item"><!----> <a href="/learn/tools/monitor.html" class="nav-link">监控系统</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="看一看" class="dropdown-title"><span class="title">看一看</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>仓库</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/watch/repository.html" class="nav-link">第三方库</a></li><li class="dropdown-subitem"><a href="/watch/website.html" class="nav-link">好玩的网站</a></li><li class="dropdown-subitem"><a href="/watch/article.html" class="nav-link">牛掰的文章</a></li><li class="dropdown-subitem"><a href="/watch/plugin.html" class="nav-link">扩展&amp;插件</a></li></ul></li><li class="dropdown-item"><h4>作品</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="http://www.5you.com/apk/384161.html" target="_blank" rel="noopener noreferrer" class="nav-link external">
  微冷知识
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></li></ul></div></div><div class="nav-item"><a href="https://github.com/fengrixin" target="_blank" rel="noopener noreferrer" class="nav-link external">
  GitHub
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="地基" class="dropdown-title"><span class="title">地基</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/learn/algorithm/" class="nav-link">数据结构和算法</a></li><li class="dropdown-item"><!----> <a href="/learn/browser/" class="nav-link">浏览器工作原理</a></li><li class="dropdown-item"><!----> <a href="/learn/js/es6.html" class="nav-link">JavaScript</a></li><li class="dropdown-item"><!----> <a href="/learn/css/" class="nav-link">CSS</a></li><li class="dropdown-item"><!----> <a href="/learn/html/" class="nav-link">HTML</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="楼层" class="dropdown-title"><span class="title">楼层</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/learn/vue/" class="nav-link">Vue</a></li><li class="dropdown-item"><!----> <a href="/learn/node/" class="nav-link">Node.js</a></li><li class="dropdown-item"><!----> <a href="/learn/mini/index.html" class="nav-link">小程序</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="电梯" class="dropdown-title"><span class="title">电梯</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/learn/tools/chain.html" class="nav-link">工具链</a></li><li class="dropdown-item"><!----> <a href="/learn/tools/publish.html" class="nav-link">发布系统</a></li><li class="dropdown-item"><!----> <a href="/learn/tools/monitor.html" class="nav-link">监控系统</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="看一看" class="dropdown-title"><span class="title">看一看</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>仓库</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/watch/repository.html" class="nav-link">第三方库</a></li><li class="dropdown-subitem"><a href="/watch/website.html" class="nav-link">好玩的网站</a></li><li class="dropdown-subitem"><a href="/watch/article.html" class="nav-link">牛掰的文章</a></li><li class="dropdown-subitem"><a href="/watch/plugin.html" class="nav-link">扩展&amp;插件</a></li></ul></li><li class="dropdown-item"><h4>作品</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="http://www.5you.com/apk/384161.html" target="_blank" rel="noopener noreferrer" class="nav-link external">
  微冷知识
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></li></ul></div></div><div class="nav-item"><a href="https://github.com/fengrixin" target="_blank" rel="noopener noreferrer" class="nav-link external">
  GitHub
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div> <!----></nav>  <ul class="sidebar-links"><li><a href="/learn/js/es6.html" class="sidebar-link">ES6+</a></li><li><a href="/learn/js/point.html" aria-current="page" class="active sidebar-link">知识点</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/js/point.html#判断类型" class="sidebar-link">判断类型</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/js/point.html#typeof" class="sidebar-link">typeof</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#instanceof" class="sidebar-link">instanceof</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#绝对正确的判断" class="sidebar-link">绝对正确的判断</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#类型转换" class="sidebar-link">类型转换</a></li></ul></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#原型-原型链" class="sidebar-link">原型&amp;原型链</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/js/point.html#对象" class="sidebar-link">对象</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#原型" class="sidebar-link">原型</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#原型链" class="sidebar-link">原型链</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#继承" class="sidebar-link">继承</a></li></ul></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#闭包与作用域" class="sidebar-link">闭包与作用域</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/js/point.html#执行上下文" class="sidebar-link">执行上下文</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#调用栈" class="sidebar-link">调用栈</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#作用域链" class="sidebar-link">作用域链</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#闭包" class="sidebar-link">闭包</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#this" class="sidebar-link">this</a></li></ul></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#异步-单线程" class="sidebar-link">异步&amp;单线程</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/js/point.html#进程、线程" class="sidebar-link">进程、线程</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#宏任务、微任务" class="sidebar-link">宏任务、微任务</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#事件循环" class="sidebar-link">事件循环</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#异步经典题目" class="sidebar-link">异步经典题目</a></li></ul></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#深拷贝" class="sidebar-link">深拷贝</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/js/point.html#json" class="sidebar-link">JSON</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#递归函数" class="sidebar-link">递归函数</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#最优方案" class="sidebar-link">最优方案</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#lodash-clonedeep" class="sidebar-link">Lodash.cloneDeep</a></li></ul></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#函数防抖-节流" class="sidebar-link">函数防抖&amp;节流</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/js/point.html#防抖" class="sidebar-link">防抖</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#节流" class="sidebar-link">节流</a></li></ul></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#函数柯里化" class="sidebar-link">函数柯里化</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#跨域" class="sidebar-link">跨域</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#网站优化" class="sidebar-link">网站优化</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/js/point.html#页面级别" class="sidebar-link">页面级别</a></li><li class="sidebar-sub-header"><a href="/learn/js/point.html#代码级别" class="sidebar-link">代码级别</a></li></ul></li></ul></li><li><a href="/learn/js/tools.html" class="sidebar-link">工具方法</a></li><li><a href="/learn/js/typescript.html" class="sidebar-link">TypeScript</a></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><blockquote><p>参考来源：
<a href="https://time.geekbang.org/column/article/83302" target="_blank" rel="noopener noreferrer">《重学前端》<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 、
<a href="https://time.geekbang.org/column/article/119046" target="_blank" rel="noopener noreferrer">《浏览器工作原理与实践》<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 、
<a href="https://ke.qq.com/course/457262" target="_blank" rel="noopener noreferrer">《中高级前端大厂面试秘籍》<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote> <h2 id="判断类型"><a href="#判断类型" class="header-anchor">#</a> 判断类型</h2> <h3 id="typeof"><a href="#typeof" class="header-anchor">#</a> typeof</h3> <p>一般用来判断基本类型，引用类型无法判断</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token comment">/** 判断所有值类型 */</span>
<span class="token keyword">typeof</span> <span class="token keyword">undefined</span> <span class="token comment">// 'undefined'</span>
<span class="token keyword">typeof</span> <span class="token string">''</span> <span class="token comment">// 'string'</span>
<span class="token keyword">typeof</span> <span class="token number">1</span> <span class="token comment">// 'number'</span>
<span class="token keyword">typeof</span> <span class="token function">BigInt</span><span class="token punctuation">(</span><span class="token number">123</span><span class="token punctuation">)</span> <span class="token comment">// 'bigint'</span>
<span class="token keyword">typeof</span> <span class="token boolean">true</span> <span class="token comment">// 'boolean'</span>
<span class="token keyword">typeof</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'s'</span><span class="token punctuation">)</span> <span class="token comment">// 'symbol'</span>

<span class="token comment">/** 特殊 */</span>
<span class="token keyword">typeof</span> <span class="token keyword">null</span> <span class="token comment">// 'object'</span>

<span class="token comment">/** 判断引用类型 */</span>
<span class="token keyword">typeof</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token comment">// 'object'</span>
<span class="token keyword">typeof</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token comment">// 'object'</span>
<span class="token keyword">typeof</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 'object' new 出来的都是对象，除了 new Function()</span>
<span class="token keyword">typeof</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 'object'</span>
<span class="token keyword">typeof</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 'object'</span>

<span class="token comment">/** 判断函数 */</span>
<span class="token keyword">typeof</span> console<span class="token punctuation">.</span>log <span class="token comment">// 'function'</span>
<span class="token keyword">typeof</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token comment">// 'function'</span>
<span class="token keyword">typeof</span> <span class="token keyword">new</span> <span class="token class-name">Function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// 'function'</span>
</code></pre></div><h3 id="instanceof"><a href="#instanceof" class="header-anchor">#</a> instanceof</h3> <p>右边的 prototype 在左边变量的原型链上
即：对象的 <strong>proto</strong> 与 函数的 prototype 在同一条原型链上</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">let</span> s <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
s <span class="token keyword">instanceof</span> <span class="token class-name">String</span>  <span class="token comment">// true</span>

Function <span class="token keyword">instanceof</span> <span class="token class-name">Function</span> <span class="token comment">// true</span>
Object <span class="token keyword">instanceof</span> <span class="token class-name">Object</span> <span class="token comment">// true</span>
Function <span class="token keyword">instanceof</span> <span class="token class-name">Object</span> <span class="token comment">// true</span>
</code></pre></div><h3 id="绝对正确的判断"><a href="#绝对正确的判断" class="header-anchor">#</a> 绝对正确的判断</h3> <p><strong>Object.prototype.toString.call(value)</strong></p> <p>在任何值上调用 Object <strong>原生的</strong> toString() 方法，都会返回一个 [object NativeConstructorName] 格式的字符串。</p> <p>因为每个类在都有一个 [[Class]] 内部属性，这个属性中就指定了上述字符串中的构造函数名。</p> <p>栗子：</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token comment">// [object Number]</span>
<span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">'1'</span><span class="token punctuation">)</span> <span class="token comment">// [object String]</span>
<span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token comment">// [object Boolean]</span>
<span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token function">BigInt</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// [object BigInt]</span>
<span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// [object Symbol]</span>
<span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token comment">// [object Null]</span>
<span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token comment">// [object Undefined]</span>
<span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">// [object Object]</span>
<span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// [object Array]</span>
<span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">// [object Function]</span>
<span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// [object Set]</span>
<span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// [object Map]</span>
</code></pre></div><blockquote><p>注意：toString 方法是可以被覆盖修改的，修改后则失去判断效果</p></blockquote> <h3 id="类型转换"><a href="#类型转换" class="header-anchor">#</a> 类型转换</h3> <p>经常涉及到类型转换的场景有以下几种：</p> <ul><li>字符串拼接</li> <li>==</li> <li>逻辑运算</li></ul> <p><img src="https://static001.geekbang.org/resource/image/71/20/71bafbd2404dc3ffa5ccf5d0ba077720.jpg" alt="">
所谓「装箱转换」，正是把基本类型转换为对应的对象（基本类型在对象中都有对应的类，Number、String、Boolean、Symbol、BigInt），它是类型转换中一种相当重要的种类</p> <h2 id="原型-原型链"><a href="#原型-原型链" class="header-anchor">#</a> 原型&amp;原型链</h2> <blockquote><p>参考文章 <br> <a href="https://mp.weixin.qq.com/s/St78Y38j3XI2_Zv57bNZ0Q" target="_blank" rel="noopener noreferrer">图解 JavaScript 原型与原型链<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <br> <a href="https://mp.weixin.qq.com/s/SgPESO46s0_vt6kSLaWO0Q" target="_blank" rel="noopener noreferrer">[JS必知必会]原型链这么看好像并不难<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <br> <a href="https://mp.weixin.qq.com/s/JzgalzgnhVjg0119xEf4BQ" target="_blank" rel="noopener noreferrer">简单粗暴地理解 JS 原型链<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <br></p></blockquote> <h3 id="对象"><a href="#对象" class="header-anchor">#</a> 对象</h3> <ul><li>所有<strong>引用类型</strong>（函数、数组、对象...）都拥有 <strong>__proto__</strong> 属性（隐式原型）</li> <li>所有<strong>函数</strong>都有用 <strong>prototype</strong> 属性（显式原型）<em>，bind 返回的函数和匿名函数除外</em></li> <li>拥有 <strong>prototype</strong> 属性的对象称为「原型对象」，原型对象在定义时就被创建</li></ul> <p><strong>prototype</strong>： 相当于一个指针，指向当前函数的「原型对象」</p> <p><strong>__proto__</strong>： 任何引用类型都有，原型对象也是对象，当然也有。也是一个指针，它指向的是<strong>产生当前对象的函数的原型对象</strong></p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">Fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token keyword">let</span> fn <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
fn<span class="token punctuation">.</span>__proto__ <span class="token operator">===</span> <span class="token class-name">Fn</span><span class="token punctuation">.</span>prototype  <span class="token comment">// true</span>
</code></pre></div><blockquote><p>__proto__ 一开始并非是 ECMAScript 标准中规定的属性，是浏览器实现的一个功能。在 ES6 后被正式纳入标准中，用于确保 Web 浏览器的兼容性 <br>
不过 ES6 后更推荐使用 Object.getPrototypeOf/Reflect.getPrototypeOf 和 Object.setPrototypeOf/Reflect.setPrototypeOf <br>
设置对象的 [[prototype]] 是一个缓慢的操作，比较耗费性能，应避免过多使用</p></blockquote> <h3 id="原型"><a href="#原型" class="header-anchor">#</a> 原型</h3> <p>JavaScript 是基于「原型」的编程语言，它们利用原型来描述对象。<em>与之对应的是另一种基于类的编程语言（比如 Java）</em></p> <p>JavaScript 的原型系统：</p> <ul><li>如果所有对象都有私有字段 [[prototype]]，就是对象的原型</li> <li>读一个属性，如果对象本身没有，则会继续访问对象的原型，直到原型为空或者找到为止</li></ul> <p>ES6 之后，JavaScript 提供了一系列内置函数来方便直接的访问操纵原型：</p> <ul><li>Object.create ：根据指定的原型创建新对象，原型可以是 null</li> <li>Object.getPrototypeOf ：获得一个对象的原型</li> <li>Object.setPrototypeOf ：设置一个对象的原型</li></ul> <h3 id="原型链"><a href="#原型链" class="header-anchor">#</a> 原型链</h3> <p>当我们访问属性时，如果当前对象没有，则会沿着原型找原型对象是否有此名称的属性，而原型对象还可能有原型，因此，会有「原型链」这一说法。</p> <p><img src="https://pic.downk.cc/item/5fbc7894b18d627113228bca.jpg" alt=""></p> <p>注意：</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code>Function<span class="token punctuation">.</span>__proto__ <span class="token operator">===</span> <span class="token class-name">Function</span><span class="token punctuation">.</span>prototype  <span class="token comment">// true</span>
</code></pre></div><h4 id="手写-instanceof"><a href="#手写-instanceof" class="header-anchor">#</a> 手写 instanceof</h4> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">instanceOf</span><span class="token punctuation">(</span><span class="token parameter">left<span class="token punctuation">,</span> right</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token keyword">if</span><span class="token punctuation">(</span>Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>left<span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token boolean">false</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">if</span><span class="token punctuation">(</span>Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>left<span class="token punctuation">)</span><span class="token operator">===</span>right<span class="token punctuation">.</span>prototype<span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> <span class="token function">instanceOf</span><span class="token punctuation">(</span>Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>left<span class="token punctuation">)</span><span class="token punctuation">,</span> right<span class="token punctuation">)</span>
<span class="token punctuation">}</span>

</code></pre></div><h4 id="手写-new"><a href="#手写-new" class="header-anchor">#</a> 手写 new</h4> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">newObj</span><span class="token punctuation">(</span><span class="token parameter">constructor<span class="token punctuation">,</span> <span class="token operator">...</span>args</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token comment">// 1. 创建一个空对象</span>
  <span class="token comment">// 2. 将对象的原型指向构造函数的原型</span>
  <span class="token keyword">const</span> obj <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>constructor<span class="token punctuation">.</span>prototype<span class="token punctuation">)</span>
  <span class="token comment">// 3. 将this绑定到obj上</span>
  <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token function">constructor</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> args<span class="token punctuation">)</span>
  <span class="token comment">// 4. 返回值判断，构造函数内有返回值res且res为对象时返回res，否则返回新对象</span>
  <span class="token keyword">return</span> res <span class="token keyword">instanceof</span> <span class="token class-name">Object</span> <span class="token operator">?</span> res <span class="token operator">:</span> obj
<span class="token punctuation">}</span>
</code></pre></div><h3 id="继承"><a href="#继承" class="header-anchor">#</a> 继承</h3> <p>原型继承</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">Father</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">Son</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token class-name">Son</span><span class="token punctuation">.</span>prototype <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token class-name">Father</span><span class="token punctuation">.</span>prototype<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    constructor<span class="token operator">:</span> <span class="token punctuation">{</span>
        value<span class="token operator">:</span> Son
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token class-name">Son</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>__proto__ <span class="token operator">===</span> <span class="token class-name">Father</span><span class="token punctuation">.</span>prototype <span class="token comment">// true</span>
</code></pre></div><h2 id="闭包与作用域"><a href="#闭包与作用域" class="header-anchor">#</a> 闭包与作用域</h2> <blockquote><p>参考文章 <br> <a href="https://time.geekbang.org/column/article/83302?utm_source=u_nav_web&amp;utm_medium=u_nav_web&amp;utm_term=u_nav_web" target="_blank" rel="noopener noreferrer">JavaScript执行（二）：闭包和执行上下文到底是怎么回事？<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <br> <a href="https://time.geekbang.org/column/article/127495?utm_source=u_nav_web&amp;utm_medium=u_nav_web&amp;utm_term=u_nav_web" target="_blank" rel="noopener noreferrer">作用域链和闭包 ：代码中出现相同的变量，JavaScript引擎是如何选择的？<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <br> <a href="https://time.geekbang.org/column/article/128427?utm_source=u_nav_web&amp;utm_medium=u_nav_web&amp;utm_term=u_nav_web" target="_blank" rel="noopener noreferrer">this：从JavaScript执行上下文的视角讲清楚this<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <br></p></blockquote> <p>JavaScript 采用的是静态作用域，也叫词法作用域。也就是说函数在定义的时候函数的作用域就决定了</p> <p>ES6 之前，只有全局作用域和函数作用域，ES6 之后才加入了块级作用域</p> <h4 id="javascript-代码的执行流程"><a href="#javascript-代码的执行流程" class="header-anchor">#</a> JavaScript 代码的执行流程</h4> <p><img src="https://static001.geekbang.org/resource/image/64/1e/649c6e3b5509ffd40e13ce9c91b3d91e.png" alt="流程图"> <img src="https://static001.geekbang.org/resource/image/06/13/0655d18ec347a95dfbf843969a921a13.png" alt="流程图"></p> <h3 id="执行上下文"><a href="#执行上下文" class="header-anchor">#</a> 执行上下文</h3> <blockquote><p>在不同的标准中，相应的术语有一定的变化</p></blockquote> <p>ES3（古典定义）</p> <ul><li>scope：作用域，也叫作用域链</li> <li>variable object：变量对象，用于存储变量的对象</li> <li>this value：this 值</li></ul> <p>ES5（改进了命名方式）</p> <ul><li>lexical environment：词法环境，当获取变量时使用</li> <li>variable environment：变量环境，当声明变量时使用</li> <li>this value：this 值</li></ul> <p>ES2018（this 值归入词法环境中，然后增加了一些其他内容）</p> <ul><li><strong>lexical environment</strong>：词法环境，当获取变量或 this 值时使用</li> <li><strong>variable environment</strong>：变量环境，当声明变量时使用</li> <li>code evaluation state：用于恢复代码执行位置</li> <li>Function：执行的任务是函数时使用，表示正在被执行的函数</li> <li>ScriptOrModule：执行的任务是脚本或者模块时使用，表示正在被执行的代码</li> <li>Realm：使用的基础库和内置对象实例</li> <li>Generator：仅生成器上下文有这个属性，表示当前生成器</li></ul> <p>虽然标准的定义一直在变化，但核心原理不变。最重要的依然是 <strong>「作用域链」「变量对象」「this」</strong></p> <h4 id="哪些情况会创建执行上下文"><a href="#哪些情况会创建执行上下文" class="header-anchor">#</a> 哪些情况会创建执行上下文？</h4> <ul><li>当 JavaScript 执行全局代码的时候，会编译全局代码并创建 <strong>「全局上下文」</strong>，而且在整个页面的生存周期内，全局执行上下文只有一份</li> <li>当调用一个函数时，函数体内的代码才会被编译，并创建 <strong>「函数执行上下文」</strong>，一般情况下，在函数执行结束之后，创建的函数执行上下文会被销毁
<blockquote><p>注意：箭头函数不会创建上下文</p></blockquote></li> <li>当使用 eval 函数时，eval 的代码也会被编译，并创建执行上下文</li></ul> <h4 id="变量提升"><a href="#变量提升" class="header-anchor">#</a> 变量提升</h4> <p><strong>var &amp; function</strong></p> <p>在代码编译阶段，JavaScript 引擎会把（var）变量和（声明式）函数的声明部分放入到了「变量环境」中。</p> <p>变量提升后，会给变量设置默认值，也就是 undefined；（声明式）函数不同于变量，会整个函数体提升。</p> <div class="language- extra-class"><pre class="language-text"><code>VariableEnvironment:
     showName -&gt;function : {console.log(&quot;showName被调用&quot;),
     myname -&gt; undefined, 
</code></pre></div><p>关于同名变量和函数的两点处理原则：</p> <ul><li>如果是同名的函数，JavaScript 编译阶段会选择最后声明的那个。</li> <li>如果变量和函数同名，那么在编译阶段，变量的声明会被忽略。
<blockquote><p>函数提升要比变量提升的优先级要高一些，且不会被变量声明覆盖，但是会被变量赋值之后覆盖。</p></blockquote></li></ul> <p><strong>let &amp; const</strong></p> <p>let 和 const 声明的变量会放入到「词法环境」的一个单独区域中，在词法环境内部维护了一个小型栈结构，按作用域链的关系把相应作用域的 let &amp; const 变量压入栈中</p> <p>let &amp; const 在块级作用域中和函数作用域一样，都是代码执行到相应位置后才去编译，将对应的变量放入到词法环境的栈顶</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">var</span> a <span class="token operator">=</span> <span class="token number">1</span>
    <span class="token keyword">let</span> b <span class="token operator">=</span> <span class="token number">2</span>
    <span class="token punctuation">{</span>
      <span class="token keyword">let</span> b <span class="token operator">=</span> <span class="token number">3</span>
      <span class="token keyword">var</span> c <span class="token operator">=</span> <span class="token number">4</span>
      <span class="token keyword">let</span> d <span class="token operator">=</span> <span class="token number">5</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>d<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div><p><img src="https://static001.geekbang.org/resource/image/f9/67/f9f67f2f53437218baef9dc724bd4c67.png" alt=""> <img src="https://static001.geekbang.org/resource/image/7e/fa/7e0f7bc362e0dea21d27dc5fb08d06fa.png" alt=""></p> <p>变量查找流程：
<img src="https://static001.geekbang.org/resource/image/06/08/06c06a756632acb12aa97b3be57bb908.png" alt=""></p> <p>当作用域块执行结束后，其内部定义的变量（let&amp;const）就会从词法环境的栈顶弹出销毁
<img src="https://static001.geekbang.org/resource/image/d4/28/d4f99640d62feba4202aa072f6369d28.png" alt=""></p> <p><strong>总结</strong>：</p> <ul><li>var 声明的变量，创建和初始化会被提升，赋值不会被提升</li> <li>let 和 const 声明的变量，创建和初始化会被提升，赋值不会被提升，但在赋值之前调取变量 JS 引擎会抛出一个错误(ReferenceError)，术语叫「暂存死区」</li> <li>声明式的 function， 创建、初始化和赋值均会被提升</li> <li>变量的查找路径为：词法环境(内部栈) -&gt; 变量环境</li></ul> <h3 id="调用栈"><a href="#调用栈" class="header-anchor">#</a> 调用栈</h3> <blockquote><p>参考文章 <br> <a href="https://time.geekbang.org/column/article/120257?utm_source=u_nav_web&amp;utm_medium=u_nav_web&amp;utm_term=u_nav_web" target="_blank" rel="noopener noreferrer">调用栈：为什么JavaScript代码会出现栈溢出？<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <br></p> <p>调用栈是用来管理函数调用关系的一种数据结构。</p></blockquote> <p>JS 引擎正是利用「栈」的这种数据结构来管理执行上下文的，在执行上下文创建好之后，JS 引擎会将执行上下文压入栈中。
通常称为「执行上下文栈」，又称「调用栈」</p> <p><strong>在浏览器端，栈底永远是 window，也就是全局执行上下文</strong></p> <p>栗子：
<img src="https://static001.geekbang.org/resource/image/87/f7/87d8bbc2bb62b03131802fba074146f7.png" alt=""></p> <h4 id="栈溢出"><a href="#栈溢出" class="header-anchor">#</a> 栈溢出</h4> <p>调用栈是有大小的，当执行上下文超过一定的数目（Chrome 大概是 2.5w 左右，不同的浏览器数目可能不太一样），JS 引擎就会抛出错误，这种错误就叫做「栈溢出」</p> <blockquote><p>递归是最容易造成栈溢出的，所以要慎用</p></blockquote> <p><img src="https://static001.geekbang.org/resource/image/b4/4d/b4f7196077d9ef4eac1ca6a279f2054d.png" alt=""></p> <h3 id="作用域链"><a href="#作用域链" class="header-anchor">#</a> 作用域链</h3> <p>什么是作用域（scope）？ 作用域是指在程序中定义变量的区域，该位置决定了变量的生命周期，通俗的理解，作用域就是变量与函数的可访问范围，即作用域控制着变量和函数的可见性和生命周期</p> <ul><li>全局作用域：变量或函数在代码中的任何地方都能访问，其生命周期伴随着页面的生命周期</li> <li>函数作用域：函数内定义的变量或函数，只能在函数内部被访问，函数执行完成后便会被销毁</li> <li>块级作用域：块中内定义的变量或函数，只能在函数内部被访问，函数执行完成后便会被销毁。<strong>值得注意的是 var 声明的变量或声明式函数依然会穿透块级作用域（函数除外）；需使用 let &amp; const 定义变量或函数，才能实现块级作用域的效果</strong> <blockquote><p>函数（所以函数作用域也可以算是一个块级作用域）、判断语句、循环语句、或者单独的 {} 都是一个块级作用域</p></blockquote></li></ul> <p>我们都知道，变量的查找首先会在自身的作用域内查找，如果自身的作用域内找不到，则会向外部的作用域查找，那么怎么知道外部是哪个作用域呢？</p> <p><strong>其实每个执行上下文的变量环境中，都会包含一个外部引用，用来指向外部的执行上下文</strong></p> <p>那么问题来了，这个外部引用是如何确定的呢？</p> <p>回到刚开始，JS 采用的是<strong>词法作用域</strong>（也就是静态作用域）。</p> <p>在代码进入编译阶段后，根据代码中变量或函数声明的位置来决定 外部引用 的</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">bar</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>myName<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">var</span> myName <span class="token operator">=</span> <span class="token string">&quot;极客邦&quot;</span>
    <span class="token function">bar</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">var</span> myName <span class="token operator">=</span> <span class="token string">&quot;极客时间&quot;</span>
<span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div><p><img src="https://static001.geekbang.org/resource/image/20/a7/20a832656434264db47c93e657e346a7.png" alt=""></p> <h4 id="变量查找路径"><a href="#变量查找路径" class="header-anchor">#</a> 变量查找路径</h4> <p><img src="https://static001.geekbang.org/resource/image/25/a7/25053af5ae30c8be991fa14631cde0a7.png" alt=""></p> <h3 id="闭包"><a href="#闭包" class="header-anchor">#</a> 闭包</h3> <p>在 JS 中，根据词法作用域的规则，内部函数总是可以访问其外部函数中声明的变量/函数</p> <p>当通过调用一个外部函数返回一个内部函数后，即使该外部函数已经执行结束了，但是内部函数引用外部函数的变量依然保存在内存中</p> <p><strong>本质是 一个绑定了外部「执行环境」的函数</strong></p> <p>栗子：</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">var</span> myName <span class="token operator">=</span> <span class="token string">&quot;极客时间&quot;</span>
    <span class="token keyword">let</span> test1 <span class="token operator">=</span> <span class="token number">1</span>
    <span class="token keyword">const</span> test2 <span class="token operator">=</span> <span class="token number">2</span>
    <span class="token keyword">var</span> innerBar <span class="token operator">=</span> <span class="token punctuation">{</span>
        <span class="token function-variable function">getName</span><span class="token operator">:</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>test1<span class="token punctuation">)</span>
            <span class="token keyword">return</span> myName
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token function-variable function">setName</span><span class="token operator">:</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">newName</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            myName <span class="token operator">=</span> newName
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> innerBar
<span class="token punctuation">}</span>
<span class="token keyword">var</span> bar <span class="token operator">=</span> <span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
bar<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">&quot;极客邦&quot;</span><span class="token punctuation">)</span>
bar<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>bar<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p><img src="https://static001.geekbang.org/resource/image/50/46/50e4ba60fc7e420e83b35b95e379b246.png" alt=""></p> <h4 id="闭包是怎么回收的"><a href="#闭包是怎么回收的" class="header-anchor">#</a> 闭包是怎么回收的？</h4> <ul><li>引用「执行环境」的函数处于函数作用域或者块级作用域内，在函数销毁后，JS 引擎便会在下一次执行垃圾回收时回收这块内存</li> <li>引用「执行环境」的函数处于全局作用域内，那么这个函数将会一直存在直至页面关闭。如果之后这个函数不再使用，就会一直占用内存造成内存泄露</li></ul> <p>所以在使用闭包的时候，尽量注意一个原则：</p> <p><strong>如果该闭包函数会一直使用，那么它可以作为全局变量存在。但如果使用频率不高，而且占用内存又比较大的话，就尽量让它成为一个局部变量</strong></p> <h3 id="this"><a href="#this" class="header-anchor">#</a> this</h3> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">let</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
    name<span class="token operator">:</span> <span class="token string">'rixin'</span><span class="token punctuation">,</span>
    <span class="token function-variable function">printName</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
       console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
obj<span class="token punctuation">.</span><span class="token function">printName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// undefined</span>
</code></pre></div><p><strong>在对象内部的方法中使用对象内部的属性是一个非常普遍的需求，但是 JS 的作用域机制并不支持这一点，基于这一点，JS 才又搞出来另一套「this 机制」</strong></p> <p>值得注意的是：作用域 和 this 并没有太大关系，是两套不同的系统，只是都存在于执行上下文中</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">let</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
    name<span class="token operator">:</span> <span class="token string">'rixin'</span><span class="token punctuation">,</span>
    <span class="token function-variable function">printName</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
       console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
obj<span class="token punctuation">.</span><span class="token function">printName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// rixin</span>
</code></pre></div><ul><li><p>全局执行上下文中的 this</p> <ul><li>在浏览器中指向的是 window 对象</li></ul></li> <li><p>函数执行上下文中的 this</p> <ul><li>普通函数中，this 指向依然是 window。「严格模式下」，this 值是 undefined，这样避免了一些因为打破数据边界造成的误操作</li> <li>函数作为对象的方法调用时，函数中 this 指向的是该对象</li> <li>通过 <a href="/learn/js/es6.html#bind、apply-call">call apply bind</a> 方法可以设置 this 的指向</li> <li>new 出来的函数，this 指向的是该函数（本质是也是 JS 引擎内部通过 call 方法重新设置了 this 指向）</li> <li>箭头函数没有执行上下文，所以 this 是外层的 this</li></ul></li></ul> <p><strong>每个函数在被调用时都会自动取得两个特殊变量：「this」和「arguments」。函数在搜索这两个变量时，只会在当前执行上下文内搜索。</strong></p> <p>因此永远不可能访问到外部函数中的这两个变量，也就出现了嵌套函数中 this 不会从外层函数继承这样的反直觉设计缺陷了。</p> <h4 id="this-的设计缺陷以及应对方案"><a href="#this-的设计缺陷以及应对方案" class="header-anchor">#</a> <a href="https://time.geekbang.org/column/article/128427" target="_blank" rel="noopener noreferrer">this 的设计缺陷以及应对方案<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></h4> <ul><li>嵌套函数中的 this 不会从外层函数中继承</li> <li>普通函数中的 this 默认指向全局对象 window（严格模式下为 undefined）</li></ul> <h4 id="this-指向问题之终极奥义"><a href="#this-指向问题之终极奥义" class="header-anchor">#</a> this 指向问题之终极奥义</h4> <p><strong>谁调用的就指向谁</strong> （嵌套函数中的 this 除外）</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">let</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span>
    name<span class="token operator">:</span> <span class="token string">'rixin'</span><span class="token punctuation">,</span>
    <span class="token function-variable function">printName</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
       console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token comment">// this1</span>
        <span class="token keyword">function</span> <span class="token function">shiftThis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
           console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token comment">//this2</span>
        <span class="token punctuation">}</span>
        <span class="token function">shiftThis</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
obj<span class="token punctuation">.</span><span class="token function">printName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// this1 指向的是 obj，this2 指向的是 window（严格模式：undefined）</span>
<span class="token keyword">let</span> obj2 <span class="token operator">=</span> obj<span class="token punctuation">.</span>printName
<span class="token function">obj2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// this1 指向的是 window，this2 指向的是 window（严格模式：undefined）</span>
</code></pre></div><h2 id="异步-单线程"><a href="#异步-单线程" class="header-anchor">#</a> 异步&amp;单线程</h2> <h3 id="进程、线程"><a href="#进程、线程" class="header-anchor">#</a> 进程、线程</h3> <ul><li>进程</li></ul> <p><strong>一个进程就是一个程序的运行实例</strong>，详细的解释就是，启动一个程序的时候，操作系统会为该程序创建一块内存，用来存放代码、运行中的数据和一个执行任务的「主线程」，我们把这样的一个运行环境叫<strong>进程</strong></p> <p>进程间相互独立，互不干扰</p> <ul><li>线程</li></ul> <p>线程是计算机最小的调度和运行单位。线程是不能单独存在的，它是由进程来启动和管理的。</p> <p>线程是依附于进程的，而进程中使用多线程并行处理能提升运算效率</p> <p>线程间可以共享进程的数据</p> <ul><li>特点
<ul><li>进程中的任意一个线程执行出错，都会导致整个进程崩溃</li> <li>线程之间共享进程中的数据</li> <li>当一个进程关闭之后，操作系统会回收进程所占用的内存</li> <li>进程之间的内容相互隔离</li></ul></li></ul> <h3 id="宏任务、微任务"><a href="#宏任务、微任务" class="header-anchor">#</a> 宏任务、微任务</h3> <blockquote><p>参考文章 <br> <a href="https://time.geekbang.org/column/article/82764" target="_blank" rel="noopener noreferrer">JavaScript执行（一）：Promise里的代码为什么比setTimeout先执行？<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> <br> <a href="https://time.geekbang.org/column/article/135624?utm_source=u_nav_web&amp;utm_medium=u_nav_web&amp;utm_term=u_nav_web" target="_blank" rel="noopener noreferrer">宏任务和微任务：不是所有任务都是一个待遇<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote> <p>宏任务就是（宿主环境）传给 JavaScript 引擎的任务 <br>
微任务就是在一个宏任务执行中，JavaScript 引擎内部产生的任务，在 JavaScript 中，只有 Promise 才会产生微任务</p> <blockquote><p>一个 JavaScript 引擎会常驻于内存中，它等待着宿主（浏览器或 Node 环境）把 JavaScript 代码或者函数传递给它执行，也称为宏任务 <br>
ES5 之后，JavaScript 引入了 Promise，这样，不需要宿主的安排，JavaScript 引擎本身也可以发起任务了，也称为微任务</p></blockquote> <h4 id="如何创建宏任务微任务"><a href="#如何创建宏任务微任务" class="header-anchor">#</a> 如何创建宏任务微任务？</h4> <table><thead><tr><th>宏任务（Macrotask）</th> <th>微任务（Microtask）</th></tr></thead> <tbody><tr><td>setTimeout</td> <td>requestAnimationFrame（有争议）</td></tr> <tr><td>setInterval</td> <td>MutationObserver（浏览器环境）</td></tr> <tr><td>MessageChannel</td> <td>Promise.[then/catch/finally]</td></tr> <tr><td>I/O，事件队列</td> <td>process.nextTick（Node环境）</td></tr> <tr><td>setImmediate（Node环境）</td> <td><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/HTML_DOM_API/Microtask_guide" target="_blank" rel="noopener noreferrer">queueMicrotask<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></td></tr> <tr><td>script（整体代码块）</td> <td></td></tr></tbody></table> <h3 id="事件循环"><a href="#事件循环" class="header-anchor">#</a> 事件循环</h3> <p>事件循环（Event Loop）是宿主（浏览器或 Node 环境）维护一个队列，核心的逻辑可以分为以下三步：</p> <p><strong>获取一段 JavaScript 代码 -&gt; 执行 -&gt; 等待</strong></p> <blockquote><p><a href="https://time.geekbang.org/column/article/132931" target="_blank" rel="noopener noreferrer">消息队列和事件循环：页面是怎么“活”起来的？<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote> <h3 id="异步经典题目"><a href="#异步经典题目" class="header-anchor">#</a> 异步经典题目</h3> <div class="language-javascript extra-class"><pre class="language-javascript"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script start'</span><span class="token punctuation">)</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">async1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'async1 start'</span><span class="token punctuation">)</span>
  <span class="token keyword">await</span> <span class="token function">async2</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'async1 end'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">async2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'async2'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token function">async1</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'setTimeout'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token parameter">resolve</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'new Promise'</span><span class="token punctuation">)</span>
  <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'promise1'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'promise2'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'script end'</span><span class="token punctuation">)</span>
</code></pre></div><p>执行结果：</p> <div class="language- extra-class"><pre class="language-text"><code>script start  // 第一个宏任务 开始
async1 start
async2
new Promise
script end  // 宏任务结束
async1 end  // 执行宏任务中的微任务
promise1
promise2  // 微任务结束

setTimeout // 第二个宏任务 开始
</code></pre></div><p>注意：</p> <blockquote><p>async 函数中，await 之后的代码是一个微任务 <br>
Chrome 73 版本乃至之前，因为 await 之后的代码被多个 Promise 包裹，所以会被放置到微任务队列的末尾，73 之后修复了这个问题</p></blockquote> <h2 id="深拷贝"><a href="#深拷贝" class="header-anchor">#</a> 深拷贝</h2> <p>测试用例</p> <div class="language-js extra-class"><pre class="language-js"><code>obj <span class="token operator">=</span> <span class="token punctuation">{</span>
    arr<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    date<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function-variable function">func</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'--'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
    inf<span class="token operator">:</span> <span class="token number">Infinity</span><span class="token punctuation">,</span>
    map<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    nan<span class="token operator">:</span> <span class="token number">NaN</span><span class="token punctuation">,</span>
    obj<span class="token operator">:</span> <span class="token punctuation">{</span>a<span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
    reg<span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">123</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span>
    set<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    symbol<span class="token operator">:</span> <span class="token function">Symbol</span><span class="token punctuation">(</span><span class="token string">'1'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    und<span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="json"><a href="#json" class="header-anchor">#</a> JSON</h3> <blockquote><p>业务中最实用，只能拷贝基本类型、数组和对象 <br>
无法拷贝 Infinity、NaN、reg(正则)、undefined、Symbol、Function、Date、Set、Map</p></blockquote> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><h3 id="递归函数"><a href="#递归函数" class="header-anchor">#</a> 递归函数</h3> <blockquote><p>相比 JSON 拷贝而言，此函数无法拷贝 reg(正则)、Function、Date、Set、Map</p></blockquote> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">cloneDeep</span><span class="token punctuation">(</span><span class="token parameter">obj</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> tempObj <span class="token operator">=</span> Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>obj <span class="token operator">&amp;&amp;</span> <span class="token keyword">typeof</span> obj <span class="token operator">===</span> <span class="token string">'object'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> key <span class="token keyword">in</span> obj<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>obj<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token keyword">typeof</span> obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'object'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          tempObj<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">cloneDeep</span><span class="token punctuation">(</span>obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
          tempObj<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> tempObj
<span class="token punctuation">}</span>
</code></pre></div><h3 id="最优方案"><a href="#最优方案" class="header-anchor">#</a> 最优方案</h3> <blockquote><p>ES6+ 的高阶写法，可以做到全类型拷贝。比 Lodash.cloneDeep 简洁</p></blockquote> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> <span class="token function-variable function">isComplexDataType</span> <span class="token operator">=</span> <span class="token parameter">obj</span> <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> obj <span class="token operator">===</span> <span class="token string">'object'</span> <span class="token operator">||</span> <span class="token keyword">typeof</span> obj <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>obj <span class="token operator">!==</span> <span class="token keyword">null</span><span class="token punctuation">)</span>

<span class="token keyword">const</span> cloneDeep <span class="token operator">=</span> <span class="token punctuation">(</span>obj<span class="token punctuation">,</span> hash <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WeakMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>hash<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> hash<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span>
    <span class="token keyword">let</span> type <span class="token operator">=</span> <span class="token punctuation">[</span>Date<span class="token punctuation">,</span> RegExp<span class="token punctuation">,</span> Set<span class="token punctuation">,</span> Map<span class="token punctuation">,</span> WeakSet<span class="token punctuation">,</span> WeakMap<span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>type<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span>obj<span class="token punctuation">.</span>constructor<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">obj<span class="token punctuation">.</span>constructor</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span>
    
    <span class="token keyword">let</span> cloneObj <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>Object<span class="token punctuation">.</span><span class="token function">getPrototypeOf</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">,</span> Object<span class="token punctuation">.</span><span class="token function">getOwnPropertyDescriptors</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    hash<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> cloneObj<span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> key <span class="token keyword">of</span> Reflect<span class="token punctuation">.</span><span class="token function">ownKeys</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        cloneObj<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token function">isComplexDataType</span><span class="token punctuation">(</span>obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token keyword">typeof</span> obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">!==</span> <span class="token string">'function'</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token function">cloneDeep</span><span class="token punctuation">(</span>obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">,</span> hash<span class="token punctuation">)</span> <span class="token operator">:</span> obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> cloneObj<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="lodash-clonedeep"><a href="#lodash-clonedeep" class="header-anchor">#</a> <a href="https://lodash.com/docs/4.17.15#cloneDeep" target="_blank" rel="noopener noreferrer">Lodash.cloneDeep<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></h3> <blockquote><p>Lodash 中的深拷贝方法，可以做到全类型深拷贝</p></blockquote> <h2 id="函数防抖-节流"><a href="#函数防抖-节流" class="header-anchor">#</a> 函数防抖&amp;节流</h2> <p>有一些场景某些函数会频繁触发，比如输入框验证，滚动条更新，用户频繁点击提交按钮等。 <br>
这时候就需要用到防抖/节流，降低触发频率</p> <h3 id="防抖"><a href="#防抖" class="header-anchor">#</a> 防抖</h3> <blockquote><p>在给定时间内，让函数只在第一次或最后一次执行</p></blockquote> <ul><li>第一次执行</li></ul> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token comment">// 普通写法</span>
<span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>
<span class="token keyword">function</span> <span class="token function">callback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span>
  <span class="token keyword">let</span> isFirst <span class="token operator">=</span> <span class="token operator">!</span>timer
  timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span>timer <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>isFirst<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">//TODO 执行</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">// 闭包写法</span>
<span class="token keyword">function</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">func<span class="token punctuation">,</span> delay</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>
  <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span>
    <span class="token keyword">let</span> isFirst <span class="token operator">=</span> <span class="token operator">!</span>timer
    timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span>timer <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">,</span> delay<span class="token punctuation">)</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>isFirst<span class="token punctuation">)</span> <span class="token function">func</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
window<span class="token punctuation">.</span>onscroll <span class="token operator">=</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
    <span class="token comment">//TODO 执行</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span>
</code></pre></div><ul><li>最后一次执行</li></ul> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token comment">// 普通写法</span>
<span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>
<span class="token keyword">function</span> <span class="token function">callback</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span>
    timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
        <span class="token comment">//TODO 执行</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token comment">// 闭包写法</span>
<span class="token keyword">function</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">func<span class="token punctuation">,</span> delay</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>
  <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span>
    timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token function">func</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span><span class="token punctuation">,</span> delay<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
window<span class="token punctuation">.</span>onscroll <span class="token operator">=</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
    <span class="token comment">//TODO 执行</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span>
</code></pre></div><ul><li>合并成一个函数</li></ul> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token comment">/**
 * 函数防抖
 *@param func 执行函数
 *@param delay 延时执行毫秒数
 *@param type true-第一次，false-最后一次
 */</span>
<span class="token keyword">function</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token parameter">func<span class="token punctuation">,</span> delay<span class="token punctuation">,</span> type<span class="token operator">=</span><span class="token boolean">false</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>
  <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>timer<span class="token punctuation">)</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timer<span class="token punctuation">)</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>type<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">let</span> isFirst <span class="token operator">=</span> <span class="token operator">!</span>timer
        timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span> timer<span class="token operator">=</span><span class="token keyword">null</span><span class="token punctuation">,</span> delay<span class="token punctuation">)</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>isFirst<span class="token punctuation">)</span> <span class="token function">func</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token punctuation">{</span>
        timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token function">func</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span><span class="token punctuation">,</span> delay<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
window<span class="token punctuation">.</span>onscroll <span class="token operator">=</span> <span class="token function">debounce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
    <span class="token comment">//TODO 执行</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span>
</code></pre></div><h3 id="节流"><a href="#节流" class="header-anchor">#</a> 节流</h3> <blockquote><p>控制函数执行的时间间隔</p></blockquote> <ul><li>间隔前触发</li></ul> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token comment">// 普通写法</span>
<span class="token keyword">let</span> prev <span class="token operator">=</span> <span class="token number">0</span>
<span class="token keyword">function</span> <span class="token function">callback</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token keyword">let</span> now <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword">if</span><span class="token punctuation">(</span>now <span class="token operator">-</span> prev <span class="token operator">&gt;</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">//TODO 执行</span>
    prev <span class="token operator">=</span> now
  <span class="token punctuation">}</span>   
<span class="token punctuation">}</span>

<span class="token comment">// 闭包写法</span>
<span class="token keyword">function</span> <span class="token function">throttle</span><span class="token punctuation">(</span><span class="token parameter">func<span class="token punctuation">,</span> delay</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> prev <span class="token operator">=</span> <span class="token number">0</span>
  <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> now <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>now <span class="token operator">-</span> prev <span class="token operator">&gt;</span> delay<span class="token punctuation">)</span><span class="token punctuation">{</span>
      <span class="token function">func</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span>
      prev <span class="token operator">=</span> now
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><ul><li>间隔后触发</li></ul> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token comment">// 普通写法</span>
<span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>
<span class="token keyword">function</span> <span class="token function">callback</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>timer<span class="token punctuation">)</span><span class="token punctuation">{</span>
    timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
        <span class="token comment">//TODO 执行</span>
        timer <span class="token operator">=</span> <span class="token keyword">null</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">// 闭包写法</span>
<span class="token keyword">function</span> <span class="token function">throttle</span><span class="token punctuation">(</span><span class="token parameter">func<span class="token punctuation">,</span> delay</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>
  <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>timer<span class="token punctuation">)</span><span class="token punctuation">{</span>
        timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
            <span class="token function">func</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span>
            timer <span class="token operator">=</span> <span class="token keyword">null</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span> delay<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><ul><li>合并</li></ul> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token comment">/**
 * 函数节流
 *@param func 执行函数
 *@param delay 延时执行毫秒数
 *@param type true-间隔开始，false-间隔结束
 */</span>
<span class="token keyword">function</span> <span class="token function">throttle</span><span class="token punctuation">(</span><span class="token parameter">func<span class="token punctuation">,</span> delay<span class="token punctuation">,</span> type<span class="token operator">=</span><span class="token boolean">true</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> prev <span class="token operator">=</span> <span class="token number">0</span>
    <span class="token keyword">let</span> timer <span class="token operator">=</span> <span class="token keyword">null</span>

  <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
     <span class="token keyword">if</span> <span class="token punctuation">(</span>type<span class="token punctuation">)</span><span class="token punctuation">{</span>
     <span class="token keyword">let</span> now <span class="token operator">=</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
         <span class="token keyword">if</span> <span class="token punctuation">(</span>now <span class="token operator">-</span> prev <span class="token operator">&gt;</span> delay<span class="token punctuation">)</span><span class="token punctuation">{</span>
           <span class="token function">func</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span>
           prev <span class="token operator">=</span> now
         <span class="token punctuation">}</span>
     <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>timer<span class="token punctuation">)</span><span class="token punctuation">{</span>
           timer <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
              <span class="token function">func</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span>
              timer <span class="token operator">=</span> <span class="token keyword">null</span>
           <span class="token punctuation">}</span><span class="token punctuation">,</span> delay<span class="token punctuation">)</span>
         <span class="token punctuation">}</span>
     <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="函数柯里化"><a href="#函数柯里化" class="header-anchor">#</a> 函数柯里化</h2> <p>把接受多个参数的函数变换成接受一个单一参数（最初函数的第一个参数）的函数，并且返回接受余下的参数而且返回结果的新函数的技术。</p> <p>简单来说就是：使用一个闭包返回一个函数。</p> <ul><li>提前绑定好某些参数的值，提高复用性</li> <li>延迟计算</li></ul> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">curry</span><span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token function">currify</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> args <span class="token operator">=</span> <span class="token class-name">Array</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>arguments<span class="token punctuation">)</span>
    <span class="token keyword">return</span> args<span class="token punctuation">.</span>length <span class="token operator">&gt;=</span> fn<span class="token punctuation">.</span>length <span class="token operator">?</span> <span class="token function">fn</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token function">currify</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token operator">...</span>args<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// 栗子 1：</span>
<span class="token keyword">let</span> props <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">{</span>name<span class="token operator">:</span> <span class="token string">'rixin'</span><span class="token punctuation">,</span> age<span class="token operator">:</span> <span class="token number">24</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>name<span class="token operator">:</span> <span class="token string">'lp'</span><span class="token punctuation">,</span> age<span class="token operator">:</span> <span class="token number">25</span><span class="token punctuation">}</span><span class="token punctuation">]</span>
<span class="token keyword">let</span> getPropsName <span class="token operator">=</span> <span class="token function">curry</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">key<span class="token punctuation">,</span> obj</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token keyword">return</span> obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">let</span> names <span class="token operator">=</span> props<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token function">getPropsName</span><span class="token punctuation">(</span><span class="token string">'name'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// ['rixin', 'lp']</span>
<span class="token keyword">let</span> ages <span class="token operator">=</span> props<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token function">getPropsName</span><span class="token punctuation">(</span><span class="token string">'age'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// [24, 25]</span>

<span class="token comment">// 栗子 2：</span>
<span class="token keyword">function</span> <span class="token function">handler</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'name: '</span><span class="token punctuation">,</span> name<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token function">handler</span><span class="token punctuation">(</span><span class="token string">'rixin'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span> <span class="token comment">// 会立即执行</span>
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token function">curry</span><span class="token punctuation">(</span>handler<span class="token punctuation">,</span><span class="token string">'rixin'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span> <span class="token comment">// 1s 后执行</span>
</code></pre></div><h2 id="跨域"><a href="#跨域" class="header-anchor">#</a> 跨域</h2> <p>跨域问题主要是因为<strong>浏览器的同源策略</strong></p> <blockquote><p>同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互，这是一个用于隔离潜在恶意文件的重要安全机制</p></blockquote> <p>解决方案 <a href="https://mp.weixin.qq.com/s/_1QYY-gwu8HFF2-8PVN0GQ" target="_blank" rel="noopener noreferrer">传送门<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> ：</p> <ul><li>JSONP</li> <li>空 iframe 加 from</li> <li>CORS</li></ul> <h2 id="网站优化"><a href="#网站优化" class="header-anchor">#</a> 网站优化</h2> <h3 id="页面级别"><a href="#页面级别" class="header-anchor">#</a> 页面级别</h3> <ul><li>资源合并</li> <li>减少请求数</li> <li>图片懒加载</li> <li>图片合并压缩</li> <li>脚本后置</li> <li>CSS 前置</li> <li>inline 脚本 defer</li> <li>域名配置时防止发生跳转</li> <li>避免重复打包模块代码</li></ul> <h3 id="代码级别"><a href="#代码级别" class="header-anchor">#</a> 代码级别</h3> <ul><li>减少 DOM 操作</li> <li>CSS 减少 Reflow</li> <li>避免使用 eval 和 Function</li> <li>减少作用域链查找</li> <li>CSS 选择符尽可能简单（浏览器对选择符是从右往左进行的）</li></ul></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">上次更新:</span> <span class="time">9/16/2021, 3:28:52 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/learn/js/es6.html" class="prev">ES6+</a></span> <span class="next"><a href="/learn/js/tools.html">工具方法</a>
      →
    </span></p></div> </main></div><div class="global-ui"></div></div>
    <script src="/assets/js/app.0696c23a.js" defer></script><script src="/assets/js/2.96f039f8.js" defer></script><script src="/assets/js/17.c016c8f3.js" defer></script>
  </body>
</html>
